#ifndef LPSOLVER_H
#define LPSOLVER_H 1

#include<iostream>

namespace LPSOLVER {

typedef double Real;
const Real EPS = 1.0E-4;
const Real INFI = 1.0E+30;

/*
Timings
	
	C++ - 0.015 msec
	Python - 4.6 msec
	Cython  - 2.9 msec
*/

/* A simple matrix class. Wraps 2 dimensional matrix to a pointer.
It provides operators to access/set any elements of matrix*/

class Matrix {
public:

    Matrix(size_t nrow, size_t ncolumn);
    ~Matrix();
		
    Matrix(const Matrix &m);

    Real operator ()(const size_t i, const size_t j) const;
	
    Real& operator ()(const size_t i, const size_t j);
		
    size_t row() const;
	
    size_t column() const;

    void print() const;
    
    void setval(size_t i,size_t j,Real val);
	
private :
    size_t nrow, ncolumn; // no of rows and columns
    Real *data; // Stores elements of matrix
	
}; //end of Matrix

inline Real Matrix::
operator ()(const size_t i, const size_t j) const //Access operator
{
    return data[i*ncolumn + j];
}
	
inline Real& Matrix::
operator ()(const size_t i, const size_t j)   // Assignment operator
{
    return data[i*ncolumn + j];
}

inline size_t Matrix::		
row() const 
{
    return nrow;
}       // returns no of rows	

inline size_t Matrix::
column() const 
{
    return ncolumn;
} // returns no of columns	


// ************************************************
/* Aeq = coefficient matrix, beq = cost vector
*/
class LpSolver
{
public:
    // Aeq = coefficient matrix of system of equations, beq = cost vector
    LpSolver(const Matrix &Aeq, const Real *beq);
	
    ~LpSolver();
	
    // function for gauss jordan elimination. row, column gives the pivot element
    void gauss_jordan(const size_t row, const size_t column);
	
    // checks if given column is corresponding to one of given equations
    bool inEqc(const size_t i);
	
    // checks if a column is in basic matrix or not
    bool in_bd(const size_t j);
	
    // checks if a column is in trac[0]
    bool in_track0(const size_t j);
			
    // calculates cost corresponding to column j of tableau
    Real costCalc(const size_t j);
	
    // calculates marginal cost
    void margcost();
	
    // calculates the result
    void getResult(Real *a);
	
    // main function which calls other members to solve the problem
    void solve(Real *a);

private:
    size_t n,m; // n -  no of equation of LP, m - no of variables
    Matrix table; // reduced simplex tableau
    Real *g; // contains cos coefficients ofdual problem
    Real *gb; // constains cost coefficients of columns in basis matrix
    size_t *td; // contains position of column of condensed simplex tableau in dual problem matrix
    size_t *bd; // contains columns of basis matrix
    Real z; // value of the objective function
    Real *mcost; // stores marginal cost of non-basic column and their corresponding column
    Matrix track; // tracks nonbasic column in tableau

};// end of LpSolver

void printvec(const size_t *vec, const size_t size);
void printvec(const Real *vec, const size_t size);
} // namespace ends

#endif	
